﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using ProtoGame.GameLib.Entities;
using Microsoft.Xna.Framework;
using ProtoGame.Input;

namespace ProtoGame.GameLib.GameComponents
{
    public abstract class TextBox<TEnum> : Microsoft.Xna.Framework.DrawableGameComponent where TEnum : struct
    {
        string fontPath;

        Queue<string> textBuffer = new Queue<string>();
        Queue<GraphicEntity> illustrationBuffer = new Queue<GraphicEntity>();

        TimeSpan escapeTimer = TimeSpan.Zero;

        public event EventHandler Finished;

        protected TextBox(string fontPath, Game game)
            : base(game)
        {
            this.fontPath = fontPath;
            IsRunning = false;
            Text = String.Empty;
            Illustration = null;
            ToShowEscape = TimeSpan.Zero;
        }

        #region Properties
        bool IsRunning
        {
            get { return Visible && Enabled; }
            set
            {
                Enabled = value;
                Visible = value;

                //if (value == false) OnFinished(this, EventArgs.Empty);
                if (value == true) ScreenState.WakeUp();
            }
        }

        protected ScreenStateEffects ScreenState { get; set; }
        protected SpriteBatch SpriteBatch { get; set; }
        protected StringSprite TextSprite { get; set; }
        protected string Text { get; set; }
        protected GraphicEntity Illustration { get; set; }
        protected StringSprite EscapeString { get; set; }
        public virtual TEnum FrameName { get; set; }
        public virtual Vector2 WidgetsOffset { get; set; }
        public virtual Vector2 Position { get; set; }
        public virtual Vector2 Dimension { get; set; }

        public virtual Color TextColor
        {
            get { return TextSprite.ColorEffects; }
            set { TextSprite.ColorEffects = value; }
        }

        public virtual Color EscapeColor
        {
            get { return EscapeString.ColorEffects; }
            set { EscapeString.ColorEffects = value; }
        }

        TimeSpan _toShowEscape = TimeSpan.Zero;
        public TimeSpan ToShowEscape
        {
            get { return _toShowEscape; }
            set
            {
                _toShowEscape = value;
                escapeTimer = value;
            }
        }

        public string EscapeText
        {
            get { return EscapeString.Text; }
            set { EscapeString.Text = value; }
        }
        #endregion

        void KillFrames()
        {
            textBuffer.Clear();
            illustrationBuffer.Clear();

            ScreenState.GoSleep();
        }

        void NextFrame()
        {
            if (textBuffer.Count > 0)
            {
                Text = textBuffer.Dequeue();
                Illustration = illustrationBuffer.Dequeue();
            }
            else
            {
                ScreenState.GoSleep();
            }
        }

        protected virtual void OnFinished(object sender, EventArgs e)
        {
            IsRunning = false;

            if (Finished != null)
                Finished(sender, e);
        }

        protected virtual void ApplyFade()
        {
            if (Illustration != null)
                Illustration.Fade = ScreenState.Fade;

            TextSprite.Fade = ScreenState.Fade;
        }

        protected virtual void PlaceWidgets()
        {
            EscapeString.Position = Position + Dimension - EscapeString.MeasureString;
        }

        protected void AddFrame(GraphicEntity illustration, string text)
        {
            textBuffer.Enqueue(text);
            illustrationBuffer.Enqueue(illustration);
        }

        public void WakeUp()
        {
            if (!IsRunning)
            {
                IsRunning = true;
                NextFrame();
            }
        }

        #region Override Members
        protected override void LoadContent()
        {
            SpriteBatch = new SpriteBatch(Game.GraphicsDevice);

            SpriteFont dialogFont = Game.Content.Load<SpriteFont>(fontPath);
            
            TextSprite = new StringSprite(dialogFont);
            
            EscapeString = new StringSprite(dialogFont);
            EscapeString.Scale = new Vector2(0.5f);
            EscapeString.Visible = false;

            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            ScreenState.Update(gameTime.ElapsedGameTime);
            if (ScreenState.IsInactive)
                OnFinished(this, EventArgs.Empty);

            IBasicInput entradas = Game.Services.GetService(typeof(IBasicInput)) as IBasicInput;
            if (ScreenState.IsActive)
            {
                if (entradas.Confirm())
                {
                    NextFrame();
                    escapeTimer = ToShowEscape;
                }
                else if (entradas.Cancel())
                    KillFrames();

                if (escapeTimer > TimeSpan.Zero)
                {
                    escapeTimer -= gameTime.ElapsedGameTime;
                    EscapeString.Visible = false;
                }
                else if (ToShowEscape > TimeSpan.Zero && !EscapeString.Visible)
                    EscapeString.Visible = true;

            }

            if (Illustration != null) Illustration.Update(gameTime);
            TextSprite.Update(gameTime);

            ApplyFade();
            PlaceWidgets();

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            if (Illustration != null)
                Illustration.Draw(SpriteBatch);

            TextSprite.Draw(SpriteBatch);

            if (EscapeString.Visible)
                EscapeString.Draw(SpriteBatch);

            base.Draw(gameTime);
        }
        #endregion
    }
}
